package netty.tcp.websocket;

import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

/**
 * 专门做事件处理相关逻辑
 * exceptionCaught 异常事件
 * channelUnregistered 断链事件
 * channelRegistered 建链事件
 * userEventTriggered 心跳检查失败事件
 *
 * @author god.yang
 */
@Slf4j
@ChannelHandler.Sharable
public class ChannelEventHandler extends ChannelDuplexHandler {

    /**
     * 如果ws请求,服务端报错,会执行此处方法,这里做日志打印,后续可做监控
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        //如果是SocketException,服务端可以选择主动断链
        log.error("error", cause);
    }

    /**
     * 用户断链后,会触发,做channel移除管理
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("断开连接,channelId:{}", ctx.channel().id().asLongText());

        Session session = SessionManager.instance().findByChannel(ctx.channel());
        SessionManager.instance().remove(session);
    }

    /**
     * 超过设定时间,没有触发交互,会触发IdleStateEvent事件
     * 连接绑定用户,会触发BindUserEvent事件
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        //如果是长时间没有数据交互,会收到IdleStateEvent事件
        if (evt instanceof IdleStateEvent idleStateEvent) {
            //并触发关闭连接事件,事件执行完成后,会执行连接关闭
            log.warn("关闭心跳超时的连接,channelId: {}", ctx.channel().id().asLongText());

            Session session = SessionManager.instance().findByChannel(ctx.channel());
            SessionManager.instance().remove(session);
            ctx.close();
        } else {//其他事件传递出去
            super.userEventTriggered(ctx, evt);
        }
    }
}
